home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
ole2book.zip
/
CHAP07.ZIP
/
CHAP07
/
PATRON
/
DOCUMENT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-07
|
22KB
|
1,019 lines
/*
* DOCUMENT.CPP
* Modifications for Chapter 7
*
* Implementation of the CPatronDoc derivation of CDocument that
* manages pages for us.
*
* Copyright (c)1993 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Software Design Engineer
* Microsoft Systems Developer Relations
*
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include <memory.h>
#include "patron.h"
/*
* CPatronDoc::CPatronDoc
* CPatronDoc::~CPatronDoc
*
* Constructor Parameters:
* hInst HINSTANCE of the application.
*/
CPatronDoc::CPatronDoc(HINSTANCE hInst)
: CDocument(hInst)
{
m_pPG=NULL;
m_lVer=VERSIONCURRENT;
m_pIStorage=NULL;
//CHAPTER7MOD
m_fPrintSetup=TRUE;
//End CHAPTER7MOD
return;
}
CPatronDoc::~CPatronDoc(void)
{
if (NULL!=m_pPG)
delete m_pPG;
if (NULL!=m_pIStorage)
m_pIStorage->Release();
CoFreeUnusedLibraries();
return;
}
/*
* CPatronDoc::FInit
*
* Purpose:
* Initializes an already created document window. The client actually
* creates the window for us, then passes that here for further
* initialization.
*
* Parameters:
* pDI LPDOCUMENTINIT containing initialization parameters.
*
* Return Value:
* BOOL TRUE if the function succeeded, FALSE otherwise.
*/
BOOL CPatronDoc::FInit(LPDOCUMENTINIT pDI)
{
//Change the stringtable range to our customization.
pDI->idsMin=IDS_DOCUMENTMIN;
pDI->idsMax=IDS_DOCUMENTMAX;
//Do default initialization
if (!CDocument::FInit(pDI))
return FALSE;
//Pages are created when we get a ::ULoad later.
return TRUE;
}
/*
* CPatronDoc::FMessageHook
*
* Purpose:
* Processes WM_SIZE for the document so we can resize the Pages window.
*
* Parameters:
* <WndProc Parameters>
* pLRes LRESULT FAR * in which to store the return value
* for the message.
*
* Return Value:
* BOOL TRUE to prevent further processing, FALSE otherwise.
*/
BOOL CPatronDoc::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam
, LPARAM lParam, LRESULT FAR *pLRes)
{
UINT dx, dy;
RECT rc;
if (WM_SIZE==iMsg && NULL!=m_pPG)
{
dx=LOWORD(lParam);
dy=HIWORD(lParam);
//Resize the Pages window to fit the new client area of the document
GetClientRect(hWnd, &rc);
m_pPG->RectSet(&rc, FALSE);
}
/*
* We return FALSE even on WM_SIZE so we can let the default procedure
* handle maximized MDI child windows appropriately.
*/
return FALSE;
}
/*
* CPatronDoc::Clear
*
* Purpose:
* Sets all contents in the document back to defaults with no filename.
*
* Paramters:
* None
*
* Return Value:
* None
*/
void CPatronDoc::Clear(void)
{
//Completely reset the pages
m_pPG->FIStorageSet(NULL, FALSE, FALSE);
CDocument::Clear();
m_lVer=VERSIONCURRENT;
return;
}
//CHAPTER7MOD
/*
* CPatronDoc::FDirtyGet
*
* Purpose:
* Returns the current dirty status of the document.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if the file is clean, FALSE otherwise.
*/
BOOL CPatronDoc::FDirtyGet()
{
BOOL fPageDirty;
fPageDirty=m_pPG->FIsDirty();
return m_fDirty | fPageDirty;
}
/*
* CPatronDoc::Delete
*
* Purpose:
* Removed the current object from the document.
*
* Paramters:
* None
*
* Return Value:
* None
*/
void CPatronDoc::Delete(void)
{
if (NULL!=m_pPG)
m_pPG->TenantDestroy();
CoFreeUnusedLibraries();
return;
}
/*
* CPatronDoc::FQueryPrinterSetup
*
* Purpose:
* Returns whether or not the Printer Setup menu item can be
* enabled. Once you create a tenant in any page, Printer Setup
* is voided simply to keep this sample simple, that is, we don't
* have to worry about reorganizing potentially large amounts
* of layout after we start plopping down objects.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE to enable the menu, FALSE otherwise.
*/
BOOL CPatronDoc::FQueryPrinterSetup(void)
{
return m_fPrintSetup;
}
/*
* CPatronDoc::FQueryObjectSelected
*
* Purpose:
* Returns whether or not there is an object selected in this
* document for Cut, Copy, Delete functions.
*
* Parameters:
* hMenu HMENU of the Edit menu.
*
* Return Value:
* BOOL TRUE if we have an object, FALSE otherwise.
*/
BOOL CPatronDoc::FQueryObjectSelected(HMENU hMenu)
{
return m_pPG->FQueryObjectSelected(hMenu);
}
//End CHAPTER7MOD
/*
* CPatronDoc::ULoad
*
* Purpose:
* Loads a given document without any user interface overwriting the
* previous contents of the editor.
*
* Parameters:
* fChangeFile BOOL indicating if we're to update the window title
* and the filename from using this file.
* pszFile LPSTR to the filename to load. Could be NULL for
* an untitled document.
*
* Return Value:
* UINT An error value from DOCERR_*
*/
UINT CPatronDoc::ULoad(BOOL fChangeFile, LPSTR pszFile)
{
RECT rc;
LPSTORAGE pIStorage;
HRESULT hr;
CLSID clsID;
DWORD dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
if (NULL==pszFile)
{
//Create a new temp file.
hr=StgCreateDocfile(NULL, dwMode | STGM_CREATE | STGM_DELETEONRELEASE
, 0, &pIStorage);
//Mark this as one of our class since we check with ReadClassStg below.
if (SUCCEEDED(hr))
WriteClassStg(pIStorage, CLSID_PatronPages);
}
else
{
hr=StgOpenStorage(pszFile, NULL, dwMode, NULL, 0, &pIStorage);
}
if (FAILED(hr))
return DOCERR_COULDNOTOPEN;
//Check if this is our type of file and exit if not.
hr=ReadClassStg(pIStorage, &clsID);
if (FAILED(hr) || !IsEqualCLSID(clsID, CLSID_PatronPages))
{
pIStorage->Release();
return DOCERR_READFAILURE;
}
//Attempt to create our contained Pages window.
m_pPG=new CPages(m_hInst, m_cf);
GetClientRect(m_hWnd, &rc);
if (!m_pPG->FInit(m_hWnd, &rc, WS_CHILD | WS_VISIBLE, ID_PAGES, NULL))
{
pIStorage->Release();
return DOCERR_READFAILURE;
}
if (!m_pPG->FIStorageSet(pIStorage, FALSE, (BOOL)(NULL==pszFile)))
{
pIStorage->Release();
return DOCERR_READFAILURE;
}
m_pIStorage=pIStorage;
Rename(pszFile);
//Do initial setup if this is a new file, otherwise Pages handles things.
if (NULL==pszFile)
{
//Go initialize the Pages for the default printer.
if (!PrinterSetup(NULL, TRUE))
return DOCERR_COULDNOTOPEN;
//Go create an initial page.
m_pPG->PageInsert(0);
}
//CHAPTER7MOD
else
m_fPrintSetup=FALSE; //Can't change an already saved configuration
//End CHAPTER7MOD
FDirtySet(FALSE);
return DOCERR_NONE;
}
/*
* CPatronDoc::USave
*
* Purpose:
* Writes the file to a known filename, requiring that the user has
* previously used FileOpen or FileSaveAs in order to have a filename.
*
* Parameters:
* uType UINT indicating the type of file the user requested
* to save in the File Save As dialog.
* pszFile LPSTR under which to save. If NULL, use the current name.
*
* Return Value:
* UINT An error value from DOCERR_*
*/
UINT CPatronDoc::USave(UINT uType, LPSTR pszFile)
{
HRESULT hr;
LPSTORAGE pIStorage;
//Save or Save As with the same file is just a commit.
if (NULL==pszFile || (NULL!=pszFile && 0==lstrcmpi(pszFile, m_szFile)))
{
WriteFmtUserTypeStg(m_pIStorage, m_cf, PSZ(IDS_CLIPBOARDFORMAT));
//Insure pages are up to date.
m_pPG->FIStorageUpdate(FALSE);
//Commit everyting
m_pIStorage->Commit(STGC_ONLYIFCURRENT);
FDirtySet(FALSE);
return DOCERR_NONE;
}
/*
* When we're given a name, open the storage, creating it new if
* it does not exist or overwriting the old one. Then ::CopyTo
* from the current to the new, ::Commit the new, then ::Release
* the old.
*/
hr=StgCreateDocfile(pszFile, STGM_TRANSACTED | STGM_READWRITE
| STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
if (FAILED(hr))
return DOCERR_COULDNOTOPEN;
WriteClassStg(pIStorage, CLSID_PatronPages);
WriteFmtUserTypeStg(pIStorage, m_cf, PSZ(IDS_CLIPBOARDFORMAT));
//Insure all pages are up-to-date.
m_pPG->FIStorageUpdate(TRUE);
//This also copies the CLSID we stuff in here on file creation.
hr=m_pIStorage->CopyTo(NULL, NULL, NULL, pIStorage);
if (FAILED(hr))
{
pIStorage->Release();
return DOCERR_WRITEFAILURE;
}
pIStorage->Commit(STGC_ONLYIFCURRENT);
/*
* Revert changes on the original storage. If this was a temp file,
* it's deleted since we used STGM_DELETEONRELEASE.
*/
m_pIStorage->Release();
//Make this new storage current
m_pIStorage=pIStorage;
m_pPG->FIStorageSet(pIStorage, TRUE, FALSE);
FDirtySet(FALSE);
Rename(pszFile); //Update caption bar.
return DOCERR_NONE;
}
//CHAPTER7MOD
/*
* CPatronDoc::FClip
*
* Purpose:
* Places a private format, a metafile, and a bitmap of the display
* on the clipboard, optionally implementing Cut by deleting the
* data in the current window after rendering.
*
* Parameters:
* hWndFrame HWND of the main window.
* fCut BOOL indicating cut (TRUE) or copy (FALSE).
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPatronDoc::FClip(HWND hWndFrame, BOOL fCut)
{
if (NULL==m_pPG)
return FALSE;
return m_pPG->TenantClip(fCut);
}
/*
* CPatronDoc::FPaste
*
* Purpose:
* Retrieves the private data format from the clipboard and sets it
* to the current figure in the editor window.
*
* Note that if this function is called, then the clipboard format
* is available because the Paste menu item is only enabled if the
* format is present.
*
* Parameters:
* hWndFrame HWND of the main window.
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPatronDoc::FPaste(HWND hWndFrame)
{
LPDATAOBJECT pIDataObject;
BOOL fRet=FALSE;
FORMATETC fe;
TENANTTYPE tType;
if (NULL==m_pPG)
return FALSE;
if (FAILED(OleGetClipboard(&pIDataObject)))
return FALSE;
//Go get the type and format we *can* paste, then actually paste it.
if (FQueryPasteFromData(pIDataObject, &fe, &tType))
fRet=FPasteFromData(pIDataObject, &fe, tType, NULL, 0L);
pIDataObject->Release();
return fRet;
}
/*
* CPatronDoc::FQueryPaste
*
* Purpose:
* Determines if we can paste data from the clipboard.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if data is available, FALSE otherwise.
*/
BOOL CPatronDoc::FQueryPaste(void)
{
LPDATAOBJECT pIDataObject;
BOOL fRet;
if (FAILED(OleGetClipboard(&pIDataObject)))
return FALSE;
fRet=FQueryPasteFromData(pIDataObject, NULL, NULL);
pIDataObject->Release();
return fRet;
}
/*
* CPatronDoc::FPasteSpecial
*
* Purpose:
* Retrieves a specific data format from the clipboard and sends it to
* the editor window appropriately.
*
* Note that if this function is called, then the appropriate format
* is available because the Paste menu item is only enabled if the
* format is present.
*
* Parameters:
* hWndFrame HWND of the main window
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPatronDoc::FPasteSpecial(HWND hWndFrame)
{
OLEUIPASTESPECIAL ps;
OLEUIPASTEENTRY rgPaste[4];
UINT uTemp;
BOOL fRet=FALSE;
if (NULL==m_pPG)
return FALSE;
_fmemset(&ps, 0, sizeof(ps));
if (FAILED(OleGetClipboard(&ps.lpSrcDataObj)))
return FALSE;
ps.cbStruct=sizeof(ps);
ps.hWndOwner=hWndFrame;
ps.dwFlags=PSF_SELECTPASTE;
ps.arrPasteEntries=rgPaste;
ps.cPasteEntries=4;
//Set up Paste Special descriptor arrays.
SETDefFormatEtc(rgPaste[0].fmtetc, m_cf, TYMED_HGLOBAL);
rgPaste[0].lpstrFormatName=PSZ(IDS_CLIPBOARDFORMAT);
rgPaste[0].lpstrResultText=PSZ(IDS_PASTEASPATRON);
rgPaste[0].dwFlags=OLEUIPASTE_PASTEONLY;
SETDefFormatEtc(rgPaste[1].fmtetc, CF_METAFILEPICT, TYMED_MFPICT);
rgPaste[1].lpstrFormatName=PSZ(IDS_PASTEMETAFILE);
rgPaste[1].lpstrResultText=PSZ(IDS_PASTEASMETAFILE);
rgPaste[1].dwFlags=OLEUIPASTE_PASTEONLY;
SETDefFormatEtc(rgPaste[2].fmtetc, CF_DIB, TYMED_HGLOBAL);
rgPaste[2].lpstrFormatName=PSZ(IDS_PASTEDIB);
rgPaste[2].lpstrResultText=PSZ(IDS_PASTEASDIB);
rgPaste[2].dwFlags=OLEUIPASTE_PASTEONLY;
SETDefFormatEtc(rgPaste[3].fmtetc, CF_BITMAP, TYMED_GDI);
rgPaste[3].lpstrFormatName=PSZ(IDS_PASTEBITMAP);
rgPaste[3].lpstrResultText=PSZ(IDS_PASTEASBITMAP);
rgPaste[3].dwFlags=OLEUIPASTE_PASTEONLY;
uTemp=OleUIPasteSpecial(&ps);
if (OLEUI_OK==uTemp)
{
fRet=FPasteFromData(ps.lpSrcDataObj, &rgPaste[ps.nSelectedIndex].fmtetc
, TENANTTYPE_STATIC, NULL, 0L);
}
ps.lpSrcDataObj->Release();
return fRet;
}
/*
* CPatronDoc::FQueryPasteFromData
* (Protected)
*
* Purpose:
* Determines if we can paste data from a data object.
*
* Parameters:
* pIDataObject LPDATAOBJECT from which we might want to paste.
* pFE LPFORMATETC in which to return the first format
* we can use. Ignored if NULL.
* ptType LPTENANTTYPE in which to store the type of object we
* can paste. Ignored if NULL.
*
* Return Value:
* BOOL TRUE if data is available, FALSE otherwise.
*/
BOOL CPatronDoc::FQueryPasteFromData(LPDATAOBJECT pIDataObject
, LPFORMATETC pFE, LPTENANTTYPE ptType)
{
FORMATETC fe;
HRESULT hr;
if (NULL!=(LPVOID)ptType)
*ptType=TENANTTYPE_STATIC;
//Any of our specific data here?
SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
hr=pIDataObject->QueryGetData(&fe);
if (NOERROR!=hr)
{
//Try metafile, DIB, then bitmap, setting fe each time for TenantCreate
SETDefFormatEtc(fe, CF_METAFILEPICT, TYMED_MFPICT);
hr=pIDataObject->QueryGetData(&fe);
if (NOERROR!=hr)
{
SETDefFormatEtc(fe, CF_DIB, TYMED_HGLOBAL);
hr=pIDataObject->QueryGetData(&fe);
if (NOERROR!=hr)
{
SETDefFormatEtc(fe, CF_BITMAP, TYMED_GDI);
hr=pIDataObject->QueryGetData(&fe);
}
}
}
if (NOERROR==hr && NULL!=pFE)
*pFE=fe;
return (NOERROR==hr);
}
/*
* CPatronDoc::FPasteFromData
* (Protected)
*
* Purpose:
* Retrieves the private data format from a data object and sets it
* to the current figure in the editor window.
*
* Parameters:
* pIDataObject LPDATAOBJECT from which to paste.
* pFE LPFORMATETC to use in the paste. Cannot be NULL.
* tType TENANTTYPE to paste.
* ppo LPPATRONOBJECT containing placement data.
* dwData DWORD extra data sensitive to tType
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPatronDoc::FPasteFromData(LPDATAOBJECT pIDataObject
, LPFORMATETC pFE, TENANTTYPE tType, LPPATRONOBJECT ppo, DWORD dwData)
{
BOOL fRet;
HRESULT hr;
PATRONOBJECT po;
STGMEDIUM stm;
if (NULL==pFE)
return FALSE;
//If we're not given any placement data, see if we can retrieve it
if (pFE->cfFormat==m_cf && NULL==ppo)
{
hr=pIDataObject->GetData(pFE, &stm);
if (SUCCEEDED(hr))
{
ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
po=*ppo;
ppo=&po;
GlobalUnlock(stm.hGlobal);
ReleaseStgMedium(&stm);
}
}
fRet=m_pPG->TenantCreate(tType, (LPVOID)pIDataObject, pFE, ppo, dwData);
if (fRet)
{
//Disable Printer Setup once we've created a tenant.
m_fPrintSetup=FALSE;
FDirtySet(TRUE);
}
return fRet;
}
//End CHAPTER7MOD
/*
* CPatronDoc::Print
*
* Purpose:
* Prints the current document.
*
* Parameters:
* hWndFrame HWND of the frame to use for dialog parents.
*
* Return Value:
* BOOL TRUE if printing happened, FALSE if it didn't start
* or didn't complete.
*/
BOOL CPatronDoc::Print(HWND hWndFrame)
{
PRINTDLG pd;
BOOL fSuccess;
memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize=sizeof(PRINTDLG);
pd.hwndOwner =hWndFrame;
pd.nCopies =1;
pd.nFromPage =-1;
pd.nToPage =-1;
pd.nMinPage =1;
pd.nMaxPage =m_pPG->NumPagesGet();
//Get the current document printer settings
pd.hDevMode=m_pPG->DevModeGet();
pd.Flags=PD_RETURNDC | PD_ALLPAGES | PD_COLLATE
| PD_HIDEPRINTTOFILE | PD_NOSELECTION;
if (!PrintDlg(&pd))
return FALSE;
//Make sure the Pages knows about any printer changes.
if (!m_pPG->DevModeSet(pd.hDevMode, pd.hDevNames))
{
GlobalFree(pd.hDevMode);
GlobalFree(pd.hDevNames);
return FALSE;
}
//Go do the actual printing.
fSuccess=m_pPG->Print(pd.hDC, PSZ(IDS_DOCUMENTNAME), pd.Flags
, pd.nFromPage, pd.nToPage, pd.nCopies);
if (!fSuccess)
MessageBox(m_hWnd, PSZ(IDS_PRINTERROR), PSZ(IDS_DOCUMENTCAPTION), MB_OK);
return fSuccess;
}
/*
* CPatronDoc::PrinterSetup
*
* Purpose:
* Selects a new printer and options for this document.
*
* Parameters:
* hWndFrame HWND of the frame to use for dialog parents.
* fDefault BOOL to avoid any dialog and just use the default.
*
* Return Value:
* UINT Undefined
*
*/
UINT CPatronDoc::PrinterSetup(HWND hWndFrame, BOOL fDefault)
{
PRINTDLG pd;
//Attempt to get printer metrics for the default printer.
memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize=sizeof(PRINTDLG);
if (fDefault)
pd.Flags=PD_RETURNDEFAULT;
else
{
pd.hwndOwner=hWndFrame;
pd.Flags=PD_PRINTSETUP;
//Get the current document printer settings
pd.hDevMode=m_pPG->DevModeGet();
}
if (!PrintDlg(&pd))
return FALSE;
if (!m_pPG->DevModeSet(pd.hDevMode, pd.hDevNames))
{
GlobalFree(pd.hDevNames);
GlobalFree(pd.hDevMode);
return FALSE;
}
FDirtySet(TRUE);
return 1;
}
/*
* CPatronDoc::NewPage
*
* Purpose:
* Creates a new page in the document's pages control after the
* current page.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the new page.
*/
UINT CPatronDoc::NewPage(void)
{
FDirtySet(TRUE);
return m_pPG->PageInsert(0);
}
/*
* CPatronDoc::DeletePage
*
* Purpose:
* Deletes the current page from the document.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the now current page.
*/
UINT CPatronDoc::DeletePage(void)
{
FDirtySet(TRUE);
return m_pPG->PageDelete(0);
}
/*
* CPatronDoc::NextPage
*
* Purpose:
* Shows the next page in the pages window.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the new page.
*/
UINT CPatronDoc::NextPage(void)
{
UINT iPage;
iPage=m_pPG->CurPageGet();
return m_pPG->CurPageSet(++iPage);
}
/*
* CPatronDoc::PreviousPage
*
* Purpose:
* Shows the previous page in the pages window.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the new page.
*/
UINT CPatronDoc::PreviousPage(void)
{
UINT iPage;
//If iPage is zero, then we wrap around to the end.
iPage=m_pPG->CurPageGet();
return m_pPG->CurPageSet(--iPage);
}
/*
* CPatronDoc::FirstPage
*
* Purpose:
* Shows the first page page in the pages window.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the new page.
*/
UINT CPatronDoc::FirstPage(void)
{
return m_pPG->CurPageSet(0);
}
/*
* CPatronDoc::LastPage
*
* Purpose:
* Shows the last page in the pages window.
*
* Parameters:
* None
*
* Return Value:
* UINT Index of the last page.
*/
UINT CPatronDoc::LastPage(void)
{
return m_pPG->CurPageSet(-1);
}